# 1.
# 基于tcp协议完成登录认证
# 客户端输入用户名密码发送到服务端
# 服务端认证发送结果到客户端
#server:
# from socket import *
#
# username1 = 'aaa'
# password1 = 123
# sk = socket(AF_INET, SOCK_STREAM)
# sk.bind(('127.0.0.1', 8080))
# sk.listen()
# conn, addr = sk.accept()
# usr = 'aaa'
# pwd = 123
# username = conn.recv(512).decode('utf-8')
# password = conn.recv(512).decode('utf-8')
# if username == usr and int(password) == pwd:
#     conn.send(bytes('登录成功', encoding='utf-8'))
# else:
#     conn.send(bytes('登录失败', encoding='utf-8'))
# conn.close()
# sk.close()
#client:
# import socket
#
# sk = socket.socket()
# sk.connect(('127.0.0.1', 8080))
# username = input('请输入用户名')

# password = input('请输入密码')
# sk.send(bytes(username, encoding='utf-8'))
# sk.send(bytes(password, encoding='utf-8'))
# a=sk.recv(1024).decode('utf-8')
# print(a)
# sk.close()
# 2，看代码写结果【如果有错误，则标注错误即可，并且假设程序报错可以继续执行】

# class Foo(object):
#     a1 = 1
#     __a2 = 2
#
#     def __init__(self, num):
#         self.num = num
#         self.__salary = 1000
#
#     def show_data(self):
#         print(self.num + self.a1)
#
#
# obj = Foo(666)
# print(obj.num)   #666
# print(obj.a1)    #1
# print(obj.__salary)  #报错，可改成obj._persoon__salary
# print(obj.__a2) # 报错，可改成obj._Foo__a2
# print(Foo.a1)  #1
# print(Foo.__a2)  #报错print(Foo._Foo__a2)
#
# 3，看代码写结果【如果有错误，则标注错误即可，并且假设程序报错可以继续执行】
#
# class Foo(object):
#     a1 = 1
#
#     def __init__(self, num):
#         self.num = num
#
#     def show_data(self):
#         print(self.num + self.a1)
#
#
# obj1 = Foo(666)
# obj2 = Foo(999)
# print(obj1.num)  #666
# print(obj1.a1)   #1
#
# obj1.num = 18
# obj1.a1 = 99
#
# print(obj1.num)  #18
# print(obj1.a1)  #99
#
# print(obj2.a1)  #1
# print(obj2.num) #999
# print(obj2.num)  #999
# print(Foo.a1) #1
# print(obj1.a1)  #99
#
# 4，看代码写结果，注意返回值。
#
# class Foo(object):
#
#     def f1(self):
#         return 999
#
#     def f2(self):
#         v = self.f1()
#         print('f2')
#         return v
#
#     def f3(self):
#         print('f3')
#         return self.f2()
#
#     def run(self):
#         result = self.f3()
#         print(result)
#
#
# obj = Foo()
# v1 = obj.run()
# print(v1)
#output:
#f3
#f2
#999
#None
# 5，看代码写结果【如果有错误，则标注错误即可，并且假设程序报错可以继续执行】
#
# class Foo(object):
#
#     def f1(self):
#         print('f1')
#
#     @classmethod
#     def f2(cls):
#         print('f2')
#
#
# obj = Foo()
# obj.f1()
# obj.f2()
#
# Foo.f1()
# Foo.f2()
#output:
#f1
#f2
#报错
#f2
# 6，看代码写结果
#
#
# class Department(object):
#     def __init__(self, title):
#         self.title = title
#
#
# class Person(object):
#     def __init__(self, name, age, depart):
#         self.name = name
#         self.age = age
#         self.depart = depart
#
#     def message(self):
#         msg = "我是%s,年龄%s,属于%s" % (self.name, self.age, self.depart.title)
#         print(msg)
#
#
# d1 = Department('人事部')
# d2 = Department('销售部')
#
# p1 = Person('武沛齐', 18, d1)
# p2 = Person('alex', 18, d1)
# p1.message()
# p2.message()
#我是武沛齐,年龄18,属于人事部
#我是alex,年龄18,属于人事部

# 7，尝试：在多进程中开启多线程
# from multiprocessing import Process
# from threading import Thread
#
#
# def func():
#     print('AAA')
#
#
# def func2():
#     for k in range(2):
#         b = Thread(target=func, )
#         b.start()
#         print('BBB')
#
#
# if __name__ == "__main__":
#     for i in range(2):
#         a = Process(target=func2, )
#         a.start()
# 8，什么是C/S架构？, B / S
# c/s架构就是client/server模式，基于客户端和服务端
# b/s架构就是client/browser模式，基于浏览器和客户端
# 9，为何基于tcp协议的通信比基于udp协议的通信更可靠？
# tcp不会产生丢包现象，因为双方每发送一条数据，都会收到一条ACK确认包
# 10，流式协议指的是什么协议，数据报协议指的是什么协议？
#流式协议：TCP协议
#数据报协议：UDP协议
# 11，什么是socket？简述基于tcp协议的套接字通信流程
# 服务端：建立套接字→绑定端口→监听（listen）→接收客户端链接→接收客户端消息/发送消息→关闭连接→关闭套接字
# 客户端：建立套接字→连接客户端ip地址和端口→发送消息/接收消息→关闭套接字
# 12，什么是粘包？ socket中造成粘包的原因是什么？ 哪些情况会发生粘包现象？
# 粘包就是由于在TCP通信中，接收方数据接收的不完整或混入了其他传输过程中的数据，原因是由于接收方并不知道发送方要发送的消息有多大，而双方的缓存有限，当数据包比较大的时候
# ,数据包就会被拆开传送，而当数据包比较小发送间隔又比较短的时候，根据tcp内部的优化算法会将小的数据包整合，这两种情况都会产生黏包

# 13，基于tcp socket，开发简单的远程命令执行程序，允许用户执行命令，并返回结果
# import socket
# import subprocess
# import json
# import struct
#
# sev = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# sev.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# sev.bind(('127.0.0.1', 5555))
# sev.listen(5)
# print('start'.center(50, '-'))
# while True:
#     conn, addr = sev.accept()
#     while True:
#         try:
#             cmd = conn.recv(1024)
#             obj = subprocess.Popen(cmd.decode(),
#                              shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#             stdout = obj.stdout.read()
#             stderr = obj.stderr.read()
#             total_size = len(stdout)+len(stderr)
#             dict_msg = {'file_name': 'a.txt',
#                         'md5': 12431564,
#                         'total_size': total_size}
#             dict_bytes = json.dumps(dict_msg).encode()
#             header = struct.pack('i', len(dict_bytes))[0]
#             conn.send(header)
#             conn.send(dict_bytes)
#             conn.send(stdout)
#             conn.send(stderr)
#         except ConnectionResetError:
#             break
#     conn.close()
# sev.close()
# import socket
# import struct
# import json
#
# cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# cli.connect(('127.0.0.1', 5555))
# while True:
#     cmd = input('-->')
#     if not cmd:
#         continue
#     cli.send(cmd.encode())
#     obj = cli.recv(4)
#     header_len = struct.unpack('i', obj)[0]
#     header = cli.recv(header_len)
#     dict_msg = json.loads(header.decode())
#     total_size = dict_msg['total_size']
#     recv_size = 0
#     recv_data = b''
#     while recv_size < total_size:
#         data = cli.recv(1024)
#         recv_size += len(data)
#         recv_data += data
#     print(recv_data.decode('gbk'))
# cli.close()
# 14，简述TCP / IP四层协议，七层协议
#应用层、表达层、会话层、传输层、网络层、数据链路层、物理层
# 15，TCP连接建立的时候3次握手，4次挥手的具体过程, 其中的每一步具体在做什么(为什么是4次挥手, 而不是3次)
# 握手：1.A向B发送建立同步请求SYN  2.B回复确认ACK包，同时也向A发送发送数据的请求  3.B再发回ACK确认包
# 挥手：1.A向B发送结束同步的请求FIN  2.B回复确认包ACK  3.B发送结束同步的请求给A  4.A发回确认B的结束同步请求
# 因为A无需传送数据给B，但并不代表B还没有数据继续传送给A，所以要将要传输的数据发送完之后再发送结束同步的请求
# 17，尝试分析TCP为什么不是两次连接?而是三次握手?
#tcp为了连接的可靠性，每一次的请求都要向对方回复一个ack确认包，所以如果双方想要满足双向的连接请求，
#最少只能是三次，两次就会缺少接收方发回的连接请求的确认包
# 18，网络编程中设计并发服务器, 使用多进程与多线程, 请问有什么区别?
#子进程相当于进程的复制品，拥有自己独立的空间，而子线程会和线程共享内存地址，但拥有自己的栈空间，
#子线程相对来说开销更小，切换、产生更快，效率更高